﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;

namespace CSharpCC
{
    class kc
    {

        [StructLayout(LayoutKind.Explicit)]
        struct union{
            [FieldOffset(0)]
            public int[] i;
            [FieldOffset(0)]
            public byte[] b;
        }

        public Action<string> output=(s)=> { };

        byte[] data;//数据段
        int[] Intdata;
        //int[] sysbol;//标识符段
        //int[] text;//代码段
        int[] stack;//栈堆

        int[] opcodes;//机器码

        string src;


        int pos,lastpos;//token位置
        int datapos;//数据位置

        int op, lastop;//指令
        int token;//
        int tokenvalue;//
        int tokentype;//
        int loc;
        int line;


        int intsizeof = 4;
        int charsizeof = 1;
        int prtsizeof = 4;

        enum tokens{
            Num = 128, Fun, Sys, Glo, Loc, Id,
            Char, Else, Enum, For, If, Int, Return, Sizeof, While,
            Assign, Cond, Lor, Lan, Or, Xor, And, Eq, Ne, Lt, Gt, Le, Ge, Shl, Shr, Add, Sub, Mul, Div, Mod, Inc, Dec, Brak
        };

        enum opcode{
            LEA, IMM, JMP, JSR, BZ, BNZ, ENT, ADJ, LEV, LI, LC, SI, SC, PSH,
            OR, XOR, AND, EQ, NE, LT, GT, LE, GE, SHL, SHR, ADD, SUB, MUL, DIV, MOD,
            OPEN, READ, CLOS, PRTF, MALC, FREE, MSET, MCMP, EXIT
        };


        enum type{ CHAR, INT, PTR };

        enum idsz:int{ Tk, Hash, Name, Class, Type, Val, HClass, HType, HVal, Idsz };

        public struct identifier
        {
            public int Token;
            public int Hash;
            public int Name;
            public int Class;
            public int Type;
            public int Val;
            public int HClass;
            public int HType;
            public int HVal;
        }

        identifier[] sysboltable;
        int sysboltableIndex;

        bool cmp(int s,int d,int len)
        {
            while (len-- != 0)
                if (src[s] != src[d]) return false;
            return true;
        }

        void nexttokens()
        {
            int offset;
            while ((token = src[pos]) != 0)
            {
                pos++;
                if (token == '\n')
                    line++;
                else if (token == '#')
                {
                    while (src[pos] != 0 && src[pos] != '\n') pos++;
                }
                else if ((token>='a'&&token<='z')|| (token >= 'A' && token <= 'Z') || token == '_')
                {
                    offset = pos - 1;
                    while ((src[pos] >= 'a' && src[pos] <= 'z') || (src[pos] >= 'A' && src[pos] <= 'Z') || (src[pos] >= '0' && src[pos] <= '9') || src[pos] == '_')
                        token = token * 147 + src[pos++];
                    token = (token << 6) + (pos - offset);
                    sysboltableIndex = 0;
                    while (sysboltable[sysboltableIndex].Token != 0)
                    {
                        if (token == sysboltable[sysboltableIndex].Hash && cmp(sysboltable[sysboltableIndex].Name, offset, pos - offset))
                        {
                            token = sysboltable[sysboltableIndex].Token;
                            return;
                        }
                        sysboltableIndex++;
                    }
                    sysboltable[sysboltableIndex].Name = offset;
                    sysboltable[sysboltableIndex].Hash = token;
                    token = sysboltable[sysboltableIndex].Token = (int)tokens.Id;
                    return;
                }
                else if (token >= '0' && token <= '9')
                {
                    if ((tokenvalue = token - '0') != 0)
                    {
                        while (src[pos] >= '0' && src[pos] <= '9')
                            tokenvalue = tokenvalue * 10 + src[pos++] - '0';
                    }
                    else if(src[pos]=='x'|| src[pos] == 'X')
                    {
                        while ((token = src[++pos]) != 0 && (token >= '0' && token <= '9') || (token >= 'a' && token <= 'f') || (token >= 'A' && token <= 'F'))
                            tokenvalue = tokenvalue * 16 + (token & 0xf) + (token >= 'A' ? 9 : 0);
                    }
                    else
                    {
                        while(src[pos] >= '0' && src[pos] <= '7')
                            tokenvalue = tokenvalue * 8 + src[pos++] - '0';
                    }
                    token = (int)tokens.Num;
                    return;
                }
                else if (token == '/')
                {
                    if (src[pos] == '/')
                    {
                        pos++;
                        while (src[pos] != 0 && src[pos] != '\n') pos++;
                    }
                    else
                    {
                        token = (int)opcode.DIV;
                        return;
                    }
                }
                else if (token == '\'' || token == '"')
                {
                    offset = datapos;
                    while (src[pos] != 0 && src[pos] != token)
                    {
                        if ((tokenvalue = src[pos++]) == '\\')
                            switch (tokenvalue = src[pos++])
                            {
                                case 'n': tokenvalue = '\n'; break;
                                case 'r': tokenvalue = '\r'; break;
                                case 't': tokenvalue = '\t'; break;
                                default:
                                    if (tokenvalue >= '0' && tokenvalue <= '9')
                                    {
                                        tokenvalue -= '0';
                                        while (src[pos] >= '0' && src[pos] <= '9')
                                            tokenvalue = tokenvalue * 10 + src[pos++] - '0';
                                        token=src[pos];
                                    }
                                    break;
                            }
                        if (token == '"') data[datapos++] = (byte)tokenvalue;
                    }
                    pos++;
                    if (token == '"')
                        tokenvalue = offset;
                    else
                        token = (int)tokens.Num;
                    return;
                }
                else
                    switch (token)
                    {
                        case '=':
                            if (src[pos] == '=')
                            {
                                pos++;
                                token = (int)tokens.Eq;
                            }
                            else
                                token = (int)tokens.Assign;
                            return;
                        case '+':
                            if (src[pos] == '+')
                            {
                                pos++;
                                token = (int)tokens.Inc;
                            }
                            else
                                token = (int)tokens.Add;
                            return;
                        case '-':
                            if (src[pos] == '-')
                            {
                                pos++;
                                token = (int)tokens.Dec;
                            }
                            else
                                token = (int)tokens.Sub;
                            return;
                        case '!':
                            if (src[pos] == '=')
                            {
                                pos++;
                                token = (int)tokens.Ne;
                            }
                            return;
                        case '<':
                            if (src[pos] == '=')
                            {
                                pos++;
                                token = (int)tokens.Le;
                            }
                            else if(src[pos] == '<')
                            {
                                pos++;
                                token = (int)tokens.Shl;
                            }
                            else
                                token = (int)tokens.Lt;
                            return;
                        case '>':
                            if (src[pos] == '=')
                            {
                                pos++;
                                token = (int)tokens.Ge;
                            }
                            else if (src[pos] == '>')
                            {
                                pos++;
                                token = (int)tokens.Shr;
                            }
                            else
                                token = (int)tokens.Gt;
                            return;
                        case '|':
                            if (src[pos] == '|')
                            {
                                pos++;
                                token = (int)tokens.Lor;
                            }
                            else
                                token = (int)tokens.Or;
                            return;
                        case '&':
                            if (src[pos] == '&')
                            {
                                pos++;
                                token = (int)tokens.Lan;
                            }
                            else
                                token = (int)tokens.And;
                            return;
                        case '^':
                            token = (int)tokens.Xor;
                            return;
                        case '%':
                            token = (int)tokens.Mod;
                            return;
                        case '*':
                            token = (int)tokens.Mul;
                            return;
                        case '[':
                            token = (int)tokens.Brak;
                            return;
                        case '?':
                            token = (int)tokens.Cond;
                            return;
                        case '~':
                        case ';':
                        case '{':
                        case '}':
                        case '(':
                        case ')':
                        case ']':
                        case ',':
                        case ':':
                            return;
                    }
            }
        }


        void exrp(int lev)
        {
            int t, lastsysbol;
            if (token==0) { throw new Exception(string.Format("{0}: unexpected eof in expression\n", line)); }
            else if (token == (int)tokens.Num)
            {
                opcodes[++op] = (int)opcode.IMM;
                opcodes[++op] = tokenvalue;
                nexttokens();
                tokentype = (int)type.INT;
            }
            else if (token == '"')
            {
                opcodes[++op] = (int)opcode.IMM;
                opcodes[++op] = tokenvalue;
                nexttokens();
                while (token == '"') nexttokens();
                //4字节对齐
                datapos = (datapos + intsizeof) & (-intsizeof);
                tokentype = (int)type.PTR;
            }
            else if (token == (int)tokens.Sizeof)
            {
                nexttokens();
                if (token == '(')
                    nexttokens();
                else
                    throw new Exception(string.Format("{0}: open paren expected in sizeof\n", line));

                tokentype = (int)type.INT;

                if (token == (int)tokens.Int)
                    nexttokens();
                else if (token == (int)tokens.Char)
                {
                    nexttokens();
                    tokentype = (int)type.CHAR;
                }
                while (token == (int)tokens.Mul)
                {
                    nexttokens();
                    tokentype += (int)type.PTR;
                }
                if (token == ')')
                    nexttokens();
                else
                    throw new Exception(string.Format("{0}: close paren expected in sizeof\n", line));
                opcodes[++op] = (int)opcode.IMM;
                opcodes[++op] = (tokentype==(int)type.CHAR)?charsizeof:intsizeof;
                tokentype = (int)type.INT;
            }
            else if (token == (int)tokens.Id)
            {
                lastsysbol = sysboltableIndex;
                nexttokens();
                if (token == '(')
                {
                    nexttokens();
                    t = 0;
                    while (token != ')')
                    {
                        exrp((int)tokens.Assign);
                        opcodes[++op] = (int)opcode.PSH;
                        t++;
                        if (token == ',')
                            nexttokens();
                    }
                    nexttokens();
                    if (sysboltable[lastsysbol].Class == (int)tokens.Sys)
                        opcodes[++op] = sysboltable[lastsysbol].Val;
                    else if(sysboltable[lastsysbol].Class == (int)tokens.Fun)
                    {
                        opcodes[++op] = (int)opcode.JSR;
                        opcodes[++op] = sysboltable[lastsysbol].Val;
                    }
                    else
                        throw new Exception(string.Format("{0}: bad function call\n", line));

                    if (t != 0)
                    {
                        opcodes[++op] = (int)opcode.ADJ;
                        opcodes[++op] = t;
                    }

                    tokentype = sysboltable[lastsysbol].Type;
                }
                else if (sysboltable[lastsysbol].Class == (int)tokens.Num)
                {
                    opcodes[++op] = (int)opcode.IMM;
                    opcodes[++op] = sysboltable[lastsysbol].Val;
                    tokentype = (int)type.INT;
                }
                else
                {
                    switch ((tokens)sysboltable[lastsysbol].Class)
                    {
                        case tokens.Loc:
                            opcodes[++op] = (int)opcode.LEA;
                            opcodes[++op] = loc - sysboltable[lastsysbol].Val;
                            break;
                        case tokens.Glo:
                            opcodes[++op] = (int)opcode.IMM;
                            opcodes[++op] = sysboltable[lastsysbol].Val;
                            break;
                        default:
                            throw new Exception(string.Format("{0}: undefined variable\n", line));
                    }
                    opcodes[++op] = (tokentype = sysboltable[lastsysbol].Type) == (int)type.CHAR ? (int)opcode.LC : (int)opcode.LI;
                }
            }
            else if (token == '(')
            {
                nexttokens();
                if(tokentype==(int)tokens.Int|| tokentype == (int)tokens.Char)
                {
                    t = (token == (int)tokens.Int) ? (int)type.INT : (int)type.CHAR;
                    nexttokens();
                    while (token == (int)tokens.Mul)
                    {
                        nexttokens();
                        t += (int)type.PTR;
                    }
                    if (token == ')')
                        nexttokens();
                    else
                        throw new Exception(string.Format("{0}: bad cast\n", line));
                    exrp((int)tokens.Inc);
                    tokentype = t;
                }
                else
                {
                    exrp((int)tokens.Assign);
                    if (token == ')')
                        nexttokens();
                    else
                        throw new Exception(string.Format("{0}: close paren expected\n", line));
                }
            }
            else if (token == (int)tokens.Mul)
            {
                nexttokens();
                exrp((int)tokens.Inc);
                if (tokentype > (int)type.INT)
                    tokentype -= (int)type.PTR;
                else
                    throw new Exception(string.Format("{0}: bad dereference\n", line));
                opcodes[++op] = (tokentype == (int)type.CHAR) ? (int)opcode.LC : (int)opcode.LI;
            }
            else if (token == (int)tokens.And)
            {
                nexttokens();
                exrp((int)tokens.Inc);

                if (opcodes[op] == (int)opcode.LC || opcodes[op] == (int)opcode.LI)
                    op--;
                else
                    throw new Exception(string.Format("{0}: bad address-of\n", line));
                tokentype += (int)type.PTR;
            }
            else if (token == '!')
            {
                nexttokens();
                exrp((int)tokens.Inc);
                opcodes[++op] = (int)opcode.PSH;
                opcodes[++op] = (int)opcode.IMM;
                opcodes[++op] = 0;
                opcodes[++op] = (int)opcode.EQ;
                tokentype = (int)type.INT;
            }
            else if (token == '~')
            {
                nexttokens();
                exrp((int)tokens.Inc);
                opcodes[++op] = (int)opcode.PSH;
                opcodes[++op] = (int)opcode.IMM;
                opcodes[++op] = -1;
                opcodes[++op] = (int)opcode.XOR;
                tokentype = (int)type.INT;
            }
            else if (token == (int)tokens.Add)
            {
                nexttokens();
                exrp((int)tokens.Inc);
                tokentype = (int)type.INT;
            }
            else if (token == (int)tokens.Sub)
            {
                nexttokens();
                opcodes[++op] = (int)opcode.IMM;
                if (token == (int)tokens.Num)
                {
                    opcodes[++op] = -tokenvalue;
                    nexttokens();
                }
                else
                {
                    opcodes[++op] = -1;
                    opcodes[++op] = (int)opcode.PSH;
                    exrp((int)tokens.Inc);
                    opcodes[++op] = (int)opcode.MUL;
                }
                tokentype = (int)type.INT;
            }
            else if(token==(int)tokens.Inc|| token == (int)tokens.Dec)
            {
                t = token;
                nexttokens();
                exrp((int)tokens.Inc);
                if (opcodes[op] == (int)opcode.LC)
                {
                    opcodes[op] = (int)opcode.PSH;
                    opcodes[++op] = (int)opcode.LC;
                }
                else if (opcodes[op] == (int)opcode.LI)
                {
                    opcodes[op] = (int)opcode.PSH;
                    opcodes[++op] = (int)opcode.LI;
                }
                else
                    throw new Exception(string.Format("{0}: bad lvalue in pre-increment\n", line));
                opcodes[++op] = (int)opcode.PSH;
                opcodes[++op] = (int)opcode.IMM;
                opcodes[++op] = (tokentype > (int)type.PTR) ? intsizeof : charsizeof;
                opcodes[++op] = (t == (int)tokens.Inc) ? (int)opcode.ADD : (int)opcode.SUB;
                opcodes[++op] = (tokentype == (int)type.CHAR) ? (int)opcode.SC : (int)opcode.SI;
            }
            else
                throw new Exception(string.Format("{0}: bad expression\n", line));


            while (token >= lev)
            {
                t = tokentype;

                switch ((tokens)token)
                {
                    case tokens.Assign:
                        nexttokens();
                        if (opcodes[op] == (int)opcode.LC || opcodes[op] == (int)opcode.LI)
                            opcodes[op] = (int)opcode.PSH;
                        else
                            throw new Exception(string.Format("{0}: bad lvalue in assignment\n", line));
                        exrp((int)tokens.Assign);
                        opcodes[++op] = ((tokentype=t)==(int)type.CHAR) ? (int)opcode.SC : (int)opcode.SI;
                        break;
                    case tokens.Cond:
                        nexttokens();
                        opcodes[++op] = (int)opcode.BZ;
                        lastsysbol = ++op;
                        exrp((int)tokens.Assign);
                        if (token == ':')
                            nexttokens();
                        else
                            throw new Exception(string.Format("{0}: conditional missing colon\n", line));
                        opcodes[lastsysbol] = op + 3;
                        opcodes[++op] = (int)opcode.JMP;
                        lastsysbol = ++op;
                        exrp((int)tokens.Cond);
                        opcodes[lastsysbol] = op + 1;
                        break;
                    case tokens.Lor:
                        nexttokens();
                        opcodes[++op] = (int)opcode.BNZ;
                        lastsysbol = ++op;
                        exrp((int)tokens.Lan);
                        opcodes[lastsysbol] = op + 1;
                        tokentype = (int)type.INT;
                        break;
                    case tokens.Lan:
                        nexttokens();
                        opcodes[++op] = (int)opcode.BZ;
                        lastsysbol = ++op;
                        exrp((int)tokens.Or);
                        opcodes[lastsysbol] = op + 1;
                        tokentype = (int)type.INT;
                        break;
                    case tokens.Or:
                        nexttokens();
                        opcodes[++op] = (int)opcode.PSH;
                        exrp((int)tokens.Xor);
                        opcodes[++op] = (int)opcode.OR;
                        tokentype = (int)type.INT;
                        break;
                    case tokens.Xor:
                        nexttokens();
                        opcodes[++op] = (int)opcode.PSH;
                        exrp((int)tokens.And);
                        opcodes[++op] = (int)opcode.XOR;
                        tokentype = (int)type.INT;
                        break;
                    case tokens.And:
                        nexttokens();
                        opcodes[++op] = (int)opcode.PSH;
                        exrp((int)tokens.Eq);
                        opcodes[++op] = (int)opcode.AND;
                        tokentype = (int)type.INT;
                        break;
                    case tokens.Eq:
                        nexttokens();
                        opcodes[++op] = (int)opcode.PSH;
                        exrp((int)tokens.Lt);
                        opcodes[++op] = (int)opcode.EQ;
                        tokentype = (int)type.INT;
                        break;
                    case tokens.Ne:
                        nexttokens();
                        opcodes[++op] = (int)opcode.PSH;
                        exrp((int)tokens.Lt);
                        opcodes[++op] = (int)opcode.NE;
                        tokentype = (int)type.INT;
                        break;
                    case tokens.Lt:
                        nexttokens();
                        opcodes[++op] = (int)opcode.PSH;
                        exrp((int)tokens.Shl);
                        opcodes[++op] = (int)opcode.LT;
                        tokentype = (int)type.INT;
                        break;
                    case tokens.Gt:
                        nexttokens();
                        opcodes[++op] = (int)opcode.PSH;
                        exrp((int)tokens.Shl);
                        opcodes[++op] = (int)opcode.LT;
                        tokentype = (int)type.INT;
                        break;
                    case tokens.Le:
                        nexttokens();
                        opcodes[++op] = (int)opcode.PSH;
                        exrp((int)tokens.Shl);
                        opcodes[++op] = (int)opcode.LE;
                        tokentype = (int)type.INT;
                        break;
                    case tokens.Ge:
                        nexttokens();
                        opcodes[++op] = (int)opcode.PSH;
                        exrp((int)tokens.Shl);
                        opcodes[++op] = (int)opcode.GE;
                        tokentype = (int)type.INT;
                        break;
                    case tokens.Shl:
                        nexttokens();
                        opcodes[++op] = (int)opcode.PSH;
                        exrp((int)tokens.Add);
                        opcodes[++op] = (int)opcode.SHL;
                        tokentype = (int)type.INT;
                        break;
                    case tokens.Shr:
                        nexttokens();
                        opcodes[++op] = (int)opcode.PSH;
                        exrp((int)tokens.Add);
                        opcodes[++op] = (int)opcode.SHR;
                        tokentype = (int)type.INT;
                        break;
                    case tokens.Add:
                        nexttokens();
                        opcodes[++op] = (int)opcode.PSH;
                        exrp((int)tokens.Mul);
                        if ((tokentype=t) > (int)type.PTR)
                        {
                            opcodes[++op] = (int)opcode.PSH;
                            opcodes[++op] = (int)opcode.IMM;
                            opcodes[++op] = intsizeof;
                            opcodes[++op] = (int)opcode.MUL;
                        }
                        opcodes[++op] = (int)opcode.ADD;
                        break;
                    case tokens.Sub:
                        nexttokens();
                        opcodes[++op] = (int)opcode.PSH;
                        exrp((int)tokens.Mul);
                        if (t > (int)type.PTR && t == tokentype)
                        {
                            opcodes[++op] = (int)opcode.SUB;
                            opcodes[++op] = (int)opcode.PSH;
                            opcodes[++op] = (int)opcode.IMM;
                            opcodes[++op] = intsizeof;
                            opcodes[++op] = (int)opcode.DIV;
                            tokentype = (int)type.INT;
                        }
                        else if ((tokentype = t) > (int)type.PTR)
                        {
                            opcodes[++op] = (int)opcode.PSH;
                            opcodes[++op] = (int)opcode.IMM;
                            opcodes[++op] = intsizeof;
                            opcodes[++op] = (int)opcode.MUL;
                            opcodes[++op] = (int)opcode.SUB;
                        }
                        else
                            opcodes[++op] = (int)opcode.SUB;
                        break;
                    case tokens.Mul:
                        nexttokens();
                        opcodes[++op] = (int)opcode.PSH;
                        exrp((int)tokens.Inc);
                        opcodes[++op] = (int)opcode.MUL;
                        tokentype = (int)type.INT;
                        break;
                    case tokens.Div:
                        nexttokens();
                        opcodes[++op] = (int)opcode.PSH;
                        exrp((int)tokens.Inc);
                        opcodes[++op] = (int)opcode.DIV;
                        tokentype = (int)type.INT;
                        break;
                    case tokens.Mod:
                        nexttokens();
                        opcodes[++op] = (int)opcode.PSH;
                        exrp((int)tokens.Inc);
                        opcodes[++op] = (int)opcode.MOD;
                        tokentype = (int)type.INT;
                        break;
                    case tokens.Inc:
                    case tokens.Dec:
                        if (opcodes[op] == (int)opcode.LC)
                        {
                            opcodes[op] = (int)opcode.PSH;
                            opcodes[++op] = (int)opcode.LC;
                        }
                        else if (opcodes[op] == (int)opcode.LI)
                        {
                            opcodes[op] = (int)opcode.PSH;
                            opcodes[++op] = (int)opcode.LI;
                        }
                        else
                            throw new Exception(string.Format("{0}: bad lvalue in post-increment\n", line));
                        opcodes[++op] = (int)opcode.PSH;
                        opcodes[++op] = (int)opcode.IMM;
                        opcodes[++op] = (tokentype > (int)type.PTR) ? intsizeof : charsizeof;
                        opcodes[++op] = (token == (int)tokens.Inc) ? (int)opcode.ADD : (int)opcode.SUB;
                        opcodes[++op] = (tokentype == (int)type.CHAR) ? (int)opcode.SC : (int)opcode.SI;

                        opcodes[++op] = (int)opcode.PSH;
                        opcodes[++op] = (int)opcode.IMM;
                        opcodes[++op] = (tokentype > (int)type.PTR) ? intsizeof : charsizeof;
                        opcodes[++op] = (token == (int)tokens.Inc) ? (int)opcode.SUB : (int)opcode.ADD;

                        nexttokens();
                        break;
                    case tokens.Brak:
                        nexttokens();
                        opcodes[++op] = (int)opcode.PSH;
                        exrp((int)tokens.Assign);
                        if (token == ']')
                            nexttokens();
                        else
                            throw new Exception(string.Format("{0}: close bracket expected\n", line));
                        if (t > (int)type.PTR)
                        {
                            opcodes[++op] = (int)opcode.PSH;
                            opcodes[++op] = (int)opcode.IMM;
                            opcodes[++op] = intsizeof;
                            opcodes[++op] = (int)opcode.MUL;
                        }
                        else if (t < (int)type.PTR)
                            throw new Exception(string.Format("{0}: pointer type expected\n", line));
                        opcodes[++op] = (int)opcode.ADD;
                        opcodes[++op] = ((tokentype = t - (int)type.PTR) == (int)type.CHAR) ? (int)opcode.LC : (int)opcode.LI;
                        break;
                    default:
                        throw new Exception(string.Format("{0}: compiler error tk={1}\n", line,token));
                }
            }
        }


        void stmt()
        {
            int a, b;
            if (token == (int)tokens.If)
            {
                nexttokens();
                if (token == '(')
                    nexttokens();
                else
                    throw new Exception(string.Format("{0}: open paren expected\n", line));
                exrp((int)tokens.Assign);
                if (token == ')')
                    nexttokens();
                else
                    throw new Exception(string.Format("{0}: open paren expected\n", line));
                opcodes[++op] = (int)opcode.BZ;
                b = ++op;
                stmt();
                if (token == (int)tokens.Else)
                {
                    opcodes[b] = op + 3;
                    opcodes[++op] = (int)opcode.JMP;
                    b = ++op;

                    nexttokens();
                    stmt();
                }
            }
            else if (token == (int)tokens.For)
            {
                int c,d;
                //for
                nexttokens();
                
                //匹配左括号
                if (token == '(')
                    nexttokens();
                else
                    throw new Exception(string.Format("{0}: open paren expected\n", line));

                //for([初始化];[条件];[执行])
                //读取初始化
                exrp((int)tokens.Assign);
                if (token == ';')
                    nexttokens();
                else
                    throw new Exception(string.Format("{0}: open paren expected\n", line));
                a = op + 1;//循环条件位置
                exrp((int)tokens.Assign);
                if (token == ';')
                    nexttokens();
                else
                    throw new Exception(string.Format("{0}: open paren expected\n", line));
                opcodes[++op] = (int)opcode.BZ;
                b = ++op;//跳出循环判断
                opcodes[++op] = (int)opcode.JMP;
                c = ++op;//跳转到循环主体
                d = op + 1;//保存循环完成执行位置
                exrp((int)tokens.Assign);
                if (token == ')')
                    nexttokens();
                else
                    throw new Exception(string.Format("{0}: open paren expected\n", line));
                opcodes[++op] = (int)opcode.JMP;
                opcodes[++op] = a;//跳转到条件判断

                opcodes[c] = op + 1;//jmp到循环主体
                stmt();

                //跳转到循环完成执行
                opcodes[++op] = (int)opcode.JMP;
                opcodes[++op] = d;

                //跳出循环
                opcodes[b] = op + 1;

            }
            else if (token == (int)tokens.While)
            {
                nexttokens();
                a = op + 1;
                if (token == '(')
                    nexttokens();
                else
                    throw new Exception(string.Format("{0}: open paren expected\n", line));
                exrp((int)tokens.Assign);
                if (token == ')')
                    nexttokens();
                else
                    throw new Exception(string.Format("{0}: open paren expected\n", line));
                opcodes[++op] = (int)opcode.BZ;
                b = ++op;
                stmt();
                opcodes[++op] = (int)opcode.JMP;
                opcodes[++op] = a;
                opcodes[b] = op + 1;
            }
            else if (token == (int)tokens.Return)
            {
                nexttokens();
                if(token!=';')
                    exrp((int)tokens.Assign);
                opcodes[++op] = (int)opcode.LEV;
                if (token == ';')
                    nexttokens();
                else
                    throw new Exception(string.Format("{0}: semicolon expected\n", line));
            }
            else if (token == '{')
            {
                nexttokens();
                while (token != '}') stmt();
                nexttokens();
            }
            else if (token == ';')
            {
                nexttokens();
            }
            else
            {
                exrp((int)tokens.Assign);
                if (token == ';')
                    nexttokens();
                else
                    throw new Exception(string.Format("{0}: semicolon expected\n", line));
            }

        }

        string keyword = "char else enum for if int return sizeof while open read close printf malloc free memset memcmp exit void main";

        public int Comper(string code,int size)
        {


            union dat = new union();
            Intdata=stack = opcodes = dat.i = new int[1024 * 3 * size];
            data = dat.b;//data
            datapos = 0;
            op = 1024 * size;
            
            sysboltable = new identifier[1024];//sysbol
            //opcodes = new int[1024 * size];//text
            //stack = new int[1024 * size];
            int i,j;
            int mainindex;
            //add key word
            src = code+'\0'+keyword+'\0';
            pos = code.Length+1;
            i = (int)tokens.Char;
            while (i <= (int)tokens.While) { nexttokens();sysboltable[sysboltableIndex].Token = i++; }
            i = (int)opcode.OPEN;
            while (i <= (int)opcode.EXIT) { nexttokens(); sysboltable[sysboltableIndex].Class = (int)tokens.Sys; sysboltable[sysboltableIndex].Type = (int)type.INT; sysboltable[sysboltableIndex].Val = i++; }


            nexttokens();
            sysboltable[sysboltableIndex].Token = (int)tokens.Char;
            nexttokens();
            mainindex = sysboltableIndex;

            //src = code;

            line = 1;
            pos = 0;
            nexttokens();

            int basetype;
            while (token != 0)
            {
                basetype = (int)type.INT;
                if (token == (int)tokens.Int) nexttokens();
                else if (token == (int)tokens.Char)
                {
                    nexttokens();
                    basetype = (int)type.CHAR;
                }
                else if (token == (int)tokens.Enum)
                {
                    nexttokens();
                    if (token != '{') nexttokens();
                    if (token == '{')
                    {
                        nexttokens();
                        i = 0;
                        while (token != '}')
                        {
                            if (token != (int)tokens.Id) throw new Exception(string.Format("{0}: bad enum identifier {1}\n", line,(char)token));
                            nexttokens();
                            if (token == (int)tokens.Assign)
                            {
                                nexttokens();
                                if (token != (int)tokens.Num) throw new Exception(string.Format("{0}: bad enum identifier {1}\n", line, (char)token));
                                i = tokenvalue;
                                nexttokens();
                            }
                            sysboltable[sysboltableIndex].Class = (int)tokens.Num;
                            sysboltable[sysboltableIndex].Type = (int)type.INT;
                            sysboltable[sysboltableIndex].Val = i++;
                            if (token == ',') nexttokens();
                        }
                        nexttokens();
                    }
                }
                while (token != ';' && token != '}')
                {
                    tokentype = basetype;
                    while (token == (int)tokens.Mul)
                    {
                        nexttokens();
                        tokentype += (int)type.PTR;
                    }
                    if (token != (int)tokens.Id) throw new Exception(string.Format("{0}: bad global declaration\n", line));
                    if (sysboltable[sysboltableIndex].Class != 0) throw new Exception(string.Format("{0}: duplicate global definition\n", line));
                    nexttokens();
                    sysboltable[sysboltableIndex].Type = tokentype;
                    if (token == '(')
                    {
                        sysboltable[sysboltableIndex].Class = (int)tokens.Fun;
                        sysboltable[sysboltableIndex].Val = op + 1;
                        nexttokens();
                        i = 0;
                        while (token != ')')
                        {
                            tokentype = (int)type.INT;
                            if (token == (int)tokens.Int) nexttokens();
                            else if (token == (int)tokens.Char)
                            {
                                nexttokens();
                                tokentype = (int)type.CHAR;
                            }
                            while(token == (int)tokens.Mul)
                            {
                                nexttokens();
                                tokentype += (int)type.PTR;
                            }
                            if (token != (int)tokens.Id) throw new Exception(string.Format("{0}: bad parameter declaration\n", line));
                            if (sysboltable[sysboltableIndex].Class == (int)tokens.Loc) throw new Exception(string.Format("{0}: duplicate parameter definition\n", line));
                            sysboltable[sysboltableIndex].HClass = sysboltable[sysboltableIndex].Class;
                            sysboltable[sysboltableIndex].Class = (int)tokens.Loc;
                            sysboltable[sysboltableIndex].HType = sysboltable[sysboltableIndex].Type;
                            sysboltable[sysboltableIndex].Type = tokentype;
                            sysboltable[sysboltableIndex].HVal = sysboltable[sysboltableIndex].Val;
                            sysboltable[sysboltableIndex].Val = i++;
                            nexttokens();
                            if (token == ',') nexttokens();
                        }
                        nexttokens();
                        if (token != '{') throw new Exception(string.Format("{0}: bad function definition\n", line));
                        loc = ++i;
                        nexttokens();
                        opcodes[++op] = (int)opcode.ENT;
                        j = ++op;
                        
                        while (token == (int)tokens.Int || token == (int)tokens.Char)
                        {
                            basetype = (token == (int)tokens.Int) ? (int)type.INT : (int)type.CHAR;
                            nexttokens();
                            while (token != ';')
                            {
                                tokentype = basetype;
                                while (token == (int)tokens.Mul)
                                {
                                    nexttokens();
                                    tokentype += (int)type.PTR;
                                }
                                if (token != (int)tokens.Id) throw new Exception(string.Format("{0}: bad global declaration\n", line));
                                if (sysboltable[sysboltableIndex].Class == (int)tokens.Loc) throw new Exception(string.Format("{0}: duplicate parameter definition\n", line));
                                sysboltable[sysboltableIndex].HClass = sysboltable[sysboltableIndex].Class;
                                sysboltable[sysboltableIndex].Class = (int)tokens.Loc;
                                sysboltable[sysboltableIndex].HType = sysboltable[sysboltableIndex].Type;
                                sysboltable[sysboltableIndex].Type = tokentype;
                                sysboltable[sysboltableIndex].HVal = sysboltable[sysboltableIndex].Val;
                                sysboltable[sysboltableIndex].Val = ++i;
                                int dp = pos;
                                nexttokens();
                                if (token == (int)tokens.Assign)
                                {
                                    pos = dp;
                                    token = (int)tokens.Id;
                                    exrp((int)tokens.Assign);
                                }
                                if (token == ',') nexttokens();
                            }
                            nexttokens();
                        }
                        opcodes[j] = i - loc;
                        while (token != '}') stmt();
                        opcodes[++op] = (int)opcode.LEV;
                        sysboltableIndex = 0;
                        while (sysboltable[sysboltableIndex].Token != 0)
                        {
                            if (sysboltable[sysboltableIndex].Class == (int)tokens.Loc)
                            {
                                sysboltable[sysboltableIndex].Class = sysboltable[sysboltableIndex].HClass;
                                sysboltable[sysboltableIndex].Type = sysboltable[sysboltableIndex].HType;
                                sysboltable[sysboltableIndex].Val = sysboltable[sysboltableIndex].HVal;
                            }
                            sysboltableIndex++;
                        }
                    }
                    else
                    {
                        sysboltable[sysboltableIndex].Class = (int)tokens.Glo;
                        sysboltable[sysboltableIndex].Val = datapos;
                        datapos += intsizeof;
                    }
                    if (token == ',') nexttokens();
                }
                nexttokens();
            }


            int pc;
            if((pc= sysboltable[mainindex].Val)==0) throw new Exception(string.Format("main() not defined\n"));
            return pc;
        }

        string getstring(int dpos)
        {
            StringBuilder sb = new StringBuilder();
            while(data[dpos]!=0)
            if (data[datapos] < 128)
                sb.Append((char)data[dpos++]);
            else
                sb.Append((char)(data[dpos++] << 8 + data[dpos++]));
            return sb.ToString();
        }

        public void run(int addr,int argc,string argv,bool debug=false)
        {
            int bp;
            int sp;
            int a=0;
            int cyc;
            int pc=addr;
            bp = sp = stack.Length - 1;
            stack[--sp] = (int)opcode.EXIT;
            stack[--sp] = (int)opcode.PSH;
            int t = sp;
            stack[--sp] = argc;
            stack[--sp] = 0;//argv
            stack[--sp] = t;

            int mcode;

            cyc = 0;
            while (true)
            {
                mcode = opcodes[pc++];
                cyc++;
                if (debug)
                {

                }
                switch ((opcode)mcode)
                {
                    case opcode.LEA:a = bp + opcodes[pc++]; break;
                    case opcode.IMM:a = opcodes[pc++];break;
                    case opcode.JMP:pc = opcodes[pc];break;
                    case opcode.JSR: stack[--sp] = pc + 1;pc = opcodes[pc]; break;
                    case opcode.BZ:pc = (a != 0) ? pc + 1 : opcodes[pc];break;
                    case opcode.BNZ: pc = (a == 0) ? pc + 1 : opcodes[pc]; break;
                    case opcode.ENT: stack[--sp] = bp;bp = sp;sp -= opcodes[pc++]; break;
                    case opcode.ADJ:sp += opcodes[pc++];break;
                    case opcode.LEV:sp = bp;bp = stack[sp++];pc = stack[sp++]; break;
                    case opcode.LI:a = Intdata[a>>2]; break;
                    case opcode.LC:a = data[a];break;
                    case opcode.SI:Intdata[stack[sp++]>>2] = a;break;
                    case opcode.SC:data[stack[sp++]] = (byte)a; break;
                    case opcode.PSH:stack[--sp] = a;break;


                    case opcode.OR:a |= stack[sp++]; break;
                    case opcode.XOR: a ^= stack[sp++]; break;
                    case opcode.AND: a &= stack[sp++]; break;
                    case opcode.EQ: a =a== stack[sp++]?1:0; break;
                    case opcode.NE: a = a != stack[sp++] ? 1 : 0; break;
                    case opcode.LT: a = stack[sp++] < a ? 1 : 0; break;
                    case opcode.GT: a = stack[sp++] > a ? 1 : 0; break;
                    case opcode.LE: a = stack[sp++] <= a ? 1 : 0; break;
                    case opcode.GE: a = stack[sp++] >= a ? 1 : 0; break;
                    case opcode.SHL: a = stack[sp++] << a; break;
                    case opcode.SHR: a = stack[sp++] >> a; break;
                    case opcode.ADD: a = stack[sp++] + a; break;
                    case opcode.SUB: a = stack[sp++] - a; break;
                    case opcode.MUL: a = stack[sp++] * a; break;
                    case opcode.DIV: a = stack[sp++] / a; break;
                    case opcode.MOD: a = stack[sp++] % a; break;

                    case opcode.OPEN: break;
                    case opcode.READ: break;
                    case opcode.CLOS: break;
                    case opcode.PRTF: output(string.Format(getstring(stack[sp+opcodes[pc+1]-1]), stack[sp + opcodes[pc + 1]-2], stack[sp + opcodes[pc + 1]-3])); break;
                    case opcode.MALC: break;
                    case opcode.FREE: break;
                    case opcode.MSET: break;
                    case opcode.MCMP: break;
                    case opcode.EXIT:
                        output(string.Format("exit({0}) cycle = {1}\n",stack[sp],cyc));
                        return;
                    default:
                        output(string.Format("unknown instruction = %d! cycle = %d\n", mcode, cyc));
                        return ;
                }
            }
        }

    }
}
